
                /*********************************************
                **                                          **
                **                                          **
                **               exchange                   **
                **                                          **
                **                                          **
                *********************************************/
                /*********************************************
                **                                          **
                **         Author Jean-Marc Adamo           **
                **       Copyright (C) 1997-2008 JMA        **
                *********************************************/



//This is the test code for an internal function 
//of ARCH groups 

/*
** process number does not matter
*/

#include "arch.h"
#include "A.utilities"

//user program

class Proc: public S_Thread{

   public:
        int pid;
        int step;
        Proc *co_operator;

        Proc(int p, int s)
                : S_Thread((Smf0_ptr)&Proc::body){pid = p; step = s;}

        void set(Proc *p){
           co_operator = p;
        }

        void body(){

               fprintf(Sdf::trace, "node %d, in proc %d at start\n",
                       Sdf::PROC_ID, pid);
               fflush(Sdf::trace);
               int i;
               for(i = 0; i < 4; i++){
                   reschedule();
               }

               if(step<1){

                   int rank;
                   MPI_Group_rank(Sdf::GROUP_WORLD, &rank);

                   fprintf(Sdf::trace, "node %d, in proc %d ***before internal_exchange, co_operator=%d\n",
                           Sdf::PROC_ID, pid, co_operator);
                   fflush(Sdf::trace);

                   int *remote_ranks;

                   if(pid==1){
                      int local_ranks[5] = {11, 12, 13, 14, 15};
                      Coll_intern::internal_exchange
                                   (local_ranks, 5, &remote_ranks, 
                                    (Thread *)(void *)co_operator);
                                            //void * casting to avoid warning
                      fprintf(Sdf::trace, "node %d, in proc %d ***after internal_exchange, remote_ranks=%d,%d,%d,%d\n",
                           Sdf::PROC_ID, pid, 
                           remote_ranks[0], remote_ranks[1], remote_ranks[2], remote_ranks[3]);
                      fflush(Sdf::trace);

                   }else{
                      int local_ranks[3] = {21, 22, 23};
                      Coll_intern::internal_exchange
                                   (local_ranks, 3, &remote_ranks, 
                                    (Thread *)(void *)co_operator);
                                            //void * casting to avoid warning
                      fprintf(Sdf::trace, "node %d, in proc %d ***after internal_exchange, remote_ranks=%d,%d,%d,%d,%d,%d\n",
                           Sdf::PROC_ID, pid, 
                           remote_ranks[0], remote_ranks[1], remote_ranks[2], remote_ranks[3], 
                           remote_ranks[4], remote_ranks[5]);
                      fflush(Sdf::trace);
                   }

                   Proc *proc1 = new Proc(pid*10 + 1, step+1);
                   Proc *proc2 = new Proc(pid*10 + 2, step+1);
                   S_Thread *proc_tabl[2] = {proc1, proc2};
                   int pri[2] = {1, 1};
                   par(2, proc_tabl, pri);
                   delete proc1;
                   delete proc2;
               }
               fprintf(Sdf::trace, "on node %d, proc %d the end at step %d\n",
                        Sdf::PROC_ID, pid, step);
               fflush(Sdf::trace);
        }
};

class Root_proc: public Thread{

   public:

        Root_proc()
                : Thread((Tmf0_ptr)&Root_proc::body){}

        void body(){

                fprintf(Sdf::trace, "node %d, in Root_proc::body1\n", Sdf::PROC_ID);
                fflush(Sdf::trace);
                Proc *proc1 = new Proc(1, 0);
                Proc *proc2 = new Proc(2, 0);
                proc1->set(proc2);
                proc2->set(proc1);
                fprintf(Sdf::trace, "node %d, in Root_proc::body2\n", Sdf::PROC_ID);
                fflush(Sdf::trace);
                S_Thread *proc_tabl[2] = {proc1, proc2};
                int pri[2] = {1, 1};
                par(2, proc_tabl, pri);
                fprintf(Sdf::trace, "node %d, in Root_proc::body4\n", Sdf::PROC_ID);
                fflush(Sdf::trace);
                delete proc1;
                delete proc2;
        }
};
//end of user program

MAIN(Root_proc, Sdf::empty, Sdf::empty, Sdf::empty)

